﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TinyEngine.Core.Parsers;
using System.Xml.Linq;
using TinyEngine.Core.Asset;
using TinyEngine.Entities;

namespace TinyEngine.Core.Entities.Parsers
{
    public class AnimatedSpriteParser : TinyEngine.Core.Parsers.IEntityParser
    {
        public System.Xml.Linq.XElement ToXmlElement(IEntity obj)
        {
            var root = new XElement(obj.GetType().Name);
            var sprite = obj as AnimatedSpriteEntity;

            ParserHelper.ParseIEntityToXml(obj, root);
            
            ParserHelper.ParseAssetHolderToXML<SpriteAsset>(obj, root);

            AnimationsToXml(sprite, root);
            return root;
        }

        private void AnimationsToXml(AnimatedSpriteEntity sprite, XElement root)
        {
            var animLib = new XElement("AnimationLibrary");
            root.Add(animLib);
            ParserHelper.ParseStringToXml(animLib, sprite.AnimationLibrary.DefaultAnimation, "DefaultAnimation");
            foreach (var anim in sprite.AnimationLibrary.Animations)
            {
                var anElement = new XElement("Animation");
                anElement.SetAttributeValue("Name", anim.Name);
                anElement.SetAttributeValue("AssetName", anim.AssetName);
                anElement.SetAttributeValue("Duration", anim.Duration.TotalSeconds.ToString());
                anElement.SetAttributeValue("Loop", anim.Loop.ToString());

                var frameNode = new XElement("Frames");
                anElement.Add(frameNode);
                if (anim.Frames.Count > 0)
                {
                    bool allSame = true;
                    var lastSize = anim.Frames[0].SourceRectangle;
                    List<XElement> framesList=new List<XElement>();
                    foreach (var frame in anim.Frames)
                    {
                        if (lastSize.Width != frame.SourceRectangle.Width || lastSize.Height != frame.SourceRectangle.Height)
                            allSame = false;

                        var frameEl = new XElement("Frame");
                        frameEl.SetAttributeValue("SourceRect", ParserHelper.RectangleToString(frame.SourceRectangle));
                        framesList.Add(frameEl);
                    }
                    if (allSame == false)
                    {
                        foreach (var item in framesList)
                        {
                            anElement.Add(item);
                        }

                    }
                    else
                    {
                        frameNode.SetAttributeValue("FrameCount", anim.Frames.Count);
                        frameNode.SetAttributeValue("RectSize", ParserHelper.VectorToString(new Microsoft.Xna.Framework.Vector2(lastSize.Width, lastSize.Height)));
                    }
                }
                animLib.Add(anElement);
            }
            
        }

        public IEntity FromXmlElement(System.Xml.Linq.XElement element)
        {
            var sp = new AnimatedSpriteEntity();

            ParserHelper.ParseXmlToIEntity(element, sp);

            LoadAnimations(element, sp);

            return sp;
        }

        private void LoadAnimations(XElement element, AnimatedSpriteEntity sp)
        {
            var animations = element.Element("AnimationLibrary");
            if (animations == null)
                return;

            
            var defaultAnimation = ParserHelper.TryParseString("DefaultAnimation", animations);
            sp.AnimationLibrary.DefaultAnimation = defaultAnimation;
            
            foreach (var item in animations.Elements())
            {
                var animation = new SpriteAnimation();
            
                animation.Name = ParserHelper.TryParseString("Name", item);
                var frameCount = item.Element("Frames").Attribute("FrameCount");
                var asset = ParserHelper.TryParseString("AssetName", item);
                double duration = ParserHelper.TryParseDouble("Duration", item);
                animation.Loop = ParserHelper.TryParseBool("Loop", item);
                animation.Duration = TimeSpan.FromSeconds(duration);
                animation.AssetName = asset;

                if (frameCount != null)
                {
                    var rect = ParserHelper.TryParseVector("RectSize", item.Element("Frames"));
                    int count = int.Parse(frameCount.Value);
                    for (int i = 0; i < count; i++)
                    {
                        var nframe=new SpriteFrame()
                        {
                            SourceRectangle = new Microsoft.Xna.Framework.Rectangle(i * (int)rect.X, 0, (int)rect.X, (int)rect.Y)
                        };
                        animation.Frames.Add(nframe);
                    }
                }
                else
                {
                    foreach (var frame in item.Element("Frames").Elements())
                    {
                        var newFrame = new SpriteFrame()
                        {
                            SourceRectangle = ParserHelper.TryParseRectangle("SourceRect", frame)
                        };
                        animation.Frames.Add(newFrame);
                    }
                }
                sp.AnimationLibrary.Animations.Add(animation);
            
            }
            
            
            if (!string.IsNullOrEmpty(defaultAnimation))
            {
                sp.PlayAnimation(defaultAnimation);
            }
        }
    }
}
